#! /usr/bin/env python

# NM64 class for Bartol stations
#
# Copyright (C) 2011-2012 Christian T. Steigies <steigies@physik.uni-kiel.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

__author__ = "Christian T. Steigies <steigies@physik.uni-kiel.de>"
__license__ = "GPL License"

"""Bartol data format
Copyright (c) 2011-2012 Christian T. Steigies <steigies@physik.uni-kiel.de>
"""

## --------------------------------------------------------------------------
#import MySQLdb # python-mysqldb

import os
import sys

# http://docs.python.org/library/datetime.html
#from datetime import datetime, date, time, timedelta
import datetime

import calendar

#from numpy import array

#http://docs.python.org/library/sqlite3.html
# SpaceWx uses CentOS5 with Python2.4 and pysqlite2
try:
    from pysqlite2 import dbapi2 as sqlite3
except ImportError:
    try:
        from sqlite3 import dbapi2 as sqlite3
    except ImportError:
        print "SQLite module not found"
        sys.exit(1)
        
from nmdb.station.station_class import station, CheckData, CheckPressure

from nmdb.tools.datetool import ParseDate

#__all__ = ["", ""]

## --------------------------------------------------------------------------

bartol_station = ["mcmu", "newk", "sopo", "thul",
                  "fsmt", "pwnk", "nain", "invk"]
bartol_longnames = {"MCMU":"McMurdo", "NEWK":"Swarthmore/Newark", "SOPO":"South Pole", "THUL":"Thule",
                    "FSMT":"Fort Smith", "PWNK":"Peawanuck", "NAIN":"Nain", "INVK": "Inuvik"}

class bartol(station):
    def __init__(self, station, mode, year=2011, month=11):
        """read data of station
        if station is empty, FAIL (no longer: read in all stations)
        read in 1h or 1m only?
        methods to return uncorrected, corrected (+eff?) and pressure
        methods to convert to NMDB specs: count per second
        """

        self.mode = mode

        self._stations={"MCMU":"McMurdo", "NEWK":"Swarthmore/Newark", "SOPO":"South Pole", "THUL":"Thule",
                        "PWNK":"Peawanuck", "FSMT":"Fort Smith", "NAIN":"Nain", "INVK": "Inuvik"}
        self._bartol_stations = []
        try:
            print "Loading data for:", self._stations[station], "|", station
        except KeyError:
            print "INVALID station:", station
            print "allowed stations are:", self._stations
            sys.exit(1)

        modes = ["1m", "1h", "1m-rt", "1h-rt", "rt", "ori", "rev"]
        if not (self.mode in modes):
            print "INVALID MODE:", self.mode
            sys.exit(1)

        station.__init__(self, station, year, month)
        self.__num = 0 # number of stations in data file

        if (self.mode == "ori" or self.mode == "1m-rt" or self.mode == "rt"):
            """real-time high resolution data, write to ori """
            self.__read_1m_rt(station)
        elif (self.mode == "rev" or self.mode == "1m"):
            """checked high resolution data, if it already exists in NMDB write to rev, new data to ori"""
            #pass # use upload_rev for this
            self.__read_1m(station)
        elif (self.mode =="1h"):
            """checked 1h data"""
            #pass # use upload_rev fo rthis
            self.__read_1h(station, year)
        elif (self.mode =="1h-rt"):
            """real-time 1h data"""
            self.__read_1h_rt(station)
        else:
            print "no valid mode:", self.mode
            sys.exit(1)

        
    def __read_1m_rt(self, station):
        """read 1min real-time data """
        
        file = "%s_QL_Minute.txt" %(station)
        self.__read_file(file)

    def __read_1m(self, station):
        """read 1min revised data """
        
        file = "%s_Minute.txt" %(station)
        self.__read_file(file)
        
    def __read_file(self, file):
        # format: yyyyy-mn-dom hh:mm:ss corr press uncorr
        #line = " "
        try:
            myfile = open(file, "r")
            line = myfile.readline() # skip the first line, which documents the file format
            while line:
                line = myfile.readline()
                if (30 < len(line) < 50): # longer line indicates description line
                    (year, month, day, hour, minute, second, dat) = ParseDate(line)
                    corr   = float(dat.split()[0])
                    press  = float(dat.split()[1])
                    uncorr = float(dat.split()[2])

                    data = [datetime.datetime(year, month, day, hour, minute, second), uncorr, press, corr]
                    #print data
                    self._c.execute('''INSERT INTO data VALUES (?, ?, ?, ?)''', data)

        except IOError:
            print "file %s not found" %(file)
            sys.exit(1)

            
    def __read_1h_rt(self, station):
        """read 1h real-time data """
        
        file = "%s_QL_Hour.txt" %(station)
        self.__read_file(file)


    def __read_1h(self, station, year):
        
        print "read_1h:", station, year
        """
=========================================================================
DATA FILE CONTENTS

All times are UT at the start of the hour interval.
Count rates are in units of hundreds of counts per hour.
Pressure is in units of millimeters of Mercury.
A zero in any data field denotes a data gap.

A line containing 42 asterisks occurs immediately preceding
and following the data, and nowhere else in this file.
Software can use this line to seek past this header material.
=========================================================================

Start Date, Time        McMurdo         Swarthmore/Newark       South Pole             Thule
YYYY MM DD HH MM   Corr Uncorr Press    Corr Uncorr Press    Corr Uncorr Press    Corr Uncorr Press
0    1  2  3  4    5    6      7        8    9      10       11   12     13       14   15     16

0         1         2         3         4         5         6         7         8         9
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789

"""
        try:
            myfile = open(file, "r")
            while line:
                line = myfile.readline()
                if line[0:16] == "Start Date, Time":        # find description of data file contents
                    stationnames = line[19:]                # station names start in column 19
                    slen = 21                               # station names are 21 characters long
                    self.__num = 1+len(stationnames)/slen   # number of stations
                    for i in range(0, self.__num):          # for all stations
                        s = stationnames[slen*i:slen*(i+1)] # extract the next station name
                        name = " ".join(s.split())          # remove white space
                        self._bartol_stations.append(name)          # add station name to list of stations
                        #print name
                        
                if line[0:42] == sep:                       # find start of data
                    break
            #print "loading for:", self._this_station # station short name
            if self._this_station:                     # get data for only one station
                valid_station = False
                for i in range(0, self.__num):          # for all stations
                    if (self._stations[self._this_station] == self._bartol_stations[i]):
                        valid_station = True
                        break                           # station found in list of stations
                if not valid_station:
                    raise ValueError                    # station not found in list of stations

            while line:                                 # read in data
                line = myfile.readline()
                if line[0:42] == sep:                   # find end of data
                    break

                #data = []                               # create a list of data
                year   = int(line.split()[0])
                month  = int(line.split()[1])
                day    = int(line.split()[2])
                hour   = int(line.split()[3])
                minute = int(line.split()[4])
                if (year != self._year):               # date is not valid
                    raise ValueError
                #data.append(datetime.datetime(year, month, day, hour, minute, 0))

                for i in range(0, self.__num):             # for all stations
                    # data for only one station
                    if (self._stations[self._this_station] == self._station[i]):
                        corr   = float(line.split()[5+3*i])
                        uncorr = float(line.split()[6+3*i])
                        press  = float(line.split()[7+3*i])                    
                        #data.append([corr, uncorr, press]) # add measurements to list of data
                        data = [datetime.datetime(year, month, day, hour, minute), uncorr, press, corr]
                        #print data
                        self._c.execute('''INSERT INTO data VALUES (?, ?, ?, ?)''', data)
                #self._data.append(data)                   # append dataset
                    
        except IOError:
            print "file %s not found" %(file)
            sys.exit(1)
        #else:
        #finally:

    def value(self, year=2000, month=1, day=1, hour=0, minute=0):
        """convert values into NMDB format:
        counts are already given as counts per second
        pressure is given in torr: convert to mbar
        CheckData|Pressure with optional range
        Check* returns NULL if input == 0 or out of range"""
        
        try:
            (utc, u, p, c) = self._value(year, month, day, hour, minute)
        except TypeError:
            return None

        uncorr = CheckData(u)
        p_mbar = CheckPressure(mbar(p))
        corr_p = CheckData(c)
        corr_e = corr_p
        
        return (utc, uncorr, p_mbar, corr_p, corr_e)

## --------------------------------------------------------------------------
def bartol_file(datadir, station, year):
    """generate filename including path which contains data for station and year
    """

    f = datadir+"BRI"+str(year)

    if station in bartol_station[0:4]:
        f = f + ".txt"

    elif station in bartol_station[4:8]:
        f = f + "B.txt"
    else:
        print "station not in Bartol data file:", station
        print "valid stations are:", bartol_station
        sys.exit(1)

    # test: filename(thul, 2011) -> /var/tmp/nmdb/BRI2011.txt
    # test: filename(invk, 2011) -> /var/tmp/nmdb/BRI2011B.txt
    return f

## --------------------------------------------------------------------------
def sqlfilename(datadir, station, year, mode="write"):
    """
    name of sqlfile to store data in.
    sqlfiles are for one year of data, currently they can not be updated, only created from scratch.
    """

    sqlfile = datadir+station.upper()+"_"+str(year)+".sqlite"

    if mode == "write":
        if os.path.isfile(sqlfile):
            print "\nsqlite file already exists:", sqlfile
            print "please remove this file before running this script"
            sys.exit(1)

    if mode == "read":
        if not os.path.isfile(sqlfile):
            print "\nsqlite file does not exists:", sqlfile
            print "please create this file with bartol2sql first."
            sys.exit(1)

    return sqlfile

## --------------------------------------------------------------------------
def bartol_names(station, myfile):
    """get longnames from BRI data file and column which matches shortname
    """
    
    line = " "
    stations = []
    
    while line:
        line = myfile.readline()
        if line[0:16] == "Start Date, Time":        # find description of data file contents
            stationnames = line[19:]                # station names start in column 19
            slen = 21                               # station names are 21 characters long
            num = 1+len(stationnames)/slen          # number of stations
            for i in range(0, num):                 # for all stations
                s = stationnames[slen*i:slen*(i+1)] # extract the next station name
                name = " ".join(s.split())          # remove white space
                stations.append(name)               # add station name to list of stations
            break # exit read loop when station names are found

    num = 0
    col = -1
    for i in stations:
        if i == bartol_longnames[station.upper()]:
            col = num
            break
        else:
            num = num +1

    return stations, col
            
## --------------------------------------------------------------------------
def bartol_data(line, col, data_year):
    """extract 1h data from Bartol file
    """

    year   = int(line.split()[0])
    month  = int(line.split()[1])
    day    = int(line.split()[2])
    hour   = int(line.split()[3])
    minute = int(line.split()[4])
    if (year != data_year):               
        raise ValueError # invalid year in Bartol data file
    
    corr_p = float(line.split()[5+3*col])
    uncorr = float(line.split()[6+3*col])
    press  = float(line.split()[7+3*col])                    

    # convert counts/100 per hour to counts/sec: *100/(60*60)
    uncorr = uncorr / 36.
    # converr pressure in torr to mbar
    press  = mbar(press)
    corr_p = corr_p / 36.
    corr_e = corr_p
    data = [datetime.datetime(year, month, day, hour, minute), uncorr, press, corr_p, corr_e]

    return data
            
## --------------------------------------------------------------------------
# move to sql module?
# break out sql usage and move to sql module as well?
def read_sql(datadir, station, year):
    """read (1h) data from sqlfile
    """
    
    sqlfile = sqlfilename(datadir, station, year, "read")
    sql_conn = sqlite3.connect(sqlfile)            
    sql_c = sql_conn.cursor()

    row = " "
    sql_c.execute('''SELECT datetime, ucorr, pressure, corr_p, corr_e FROM data ORDER BY datetime''')

    while row:
        row = sql_c.fetchone() # should return only one line, or None
        print row

## --------------------------------------------------------------------------
def mbar(torr):
    """ convert torr into mbar"""

    return (1000.*torr/750.06)


## --------------------------------------------------------------------------
if __name__=="__main__":
    print "This is the bartol module."


